package com.dotmedia.core;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import org.apache.log4j.Logger;

/**
 * This class is the database access service. This is a one single point from which all the database activities will take place.
 * 
 * @author siddharthsaha
 * 
 */
public class DatabaseAccessService {
	private static DatabaseAccessService instance;
	private EntityManagerFactory entityManagerFactory;
	private EntityManager entityManager;
	private static Logger logger = Logger.getLogger("DatabaseAccessService");

	public static synchronized DatabaseAccessService getInstance() {
		if (instance == null) {
			instance = new DatabaseAccessService();
		}
		return instance;
	}

	private DatabaseAccessService() {
		logger.info("Creating EntityManagerFactory in constructor");
		entityManagerFactory = Persistence.createEntityManagerFactory("strutspersistenceunit");
		if (entityManagerFactory == null) {
			logger.error("EntityManagerFactory could not be created in constructor");
		} else {
			logger.info("EntityManagerFactory successfully created in constructor");
			entityManager = entityManagerFactory.createEntityManager();
			if (entityManager == null) {
				logger.error("EntityManager could not be created in the constructor of DatabaseAccessService");
			} else {
				logger.info("EnityManager was successfully created in the constructor of DatabaseAccessService");
			}
		}
	}

	/**
	 * This method will persist the object passed to the method in the database. This method must be called from methods which needs a database
	 * operation to persist. This is a generic method and will work for all kinds of entities and so it takes as argument an Object
	 * 
	 * @param object
	 *        The object which is to be persisted
	 * @return Returns 0 id successful else returns 1
	 */
	public int persistEntity(Object object) {
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		if (entityManager != null) {
			logger.info("Obtained a entity manager in persistEntity() method");
			entityManager.getTransaction().begin();
			// persist the object to the database
			logger.info("Persisting the object into the database");
			entityManager.persist(object);
			try {
				entityManager.getTransaction().commit();
			} catch (Exception exception) {
				logger.error(exception.getMessage());
				logger.error(exception);
			}
			entityManager.close();
			logger.info("Persisted the object into the database");
			return 0;
		} else {
			logger.error("Could not get entity manager in persistEntity() method");
			return 1;
		}
	}

	/**
	 * This method removes the entity which is passed to the method from the database
	 * 
	 * @param object
	 *        The object which needs to be removed.
	 * @return Returns 0 if successful else returns 1
	 */
	public int removeEntity(Object object, int id) {
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		if (entityManager != null) {
			logger.info("Obtained an entityManager in removeEntity method");
			entityManager.getTransaction().begin();
			logger.info("Removing an object from the database");
			Object foundObject = entityManager.find(object.getClass(), id);
			entityManager.remove(foundObject);
			logger.info("Removed an object from the database");
			entityManager.getTransaction().commit();
			entityManager.close();
			return 0;
		} else {
			logger.error("Could not get entityManager in removeEntity method");
			return 1;
		}
	}

	/**
	 * This method updates the entity which is already present in the database. It is the responsibility of the method which calls this method to
	 * ensure that such an object is already present in the database. Otherwise this method will not run properly as well as not give any error
	 * 
	 * @param object
	 *        The object which needs to updated
	 * @return Returns 0 if successful else returns 1
	 */
	public int updateEntity(Object object) {
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		if (entityManager != null) {
			logger.info("Obtained an entityManager in updateEntity method");
			logger.info("Updating the object in the database");
			entityManager.getTransaction().begin();
			entityManager.merge(object);
			entityManager.getTransaction().commit();
			entityManager.close();
			return 0;
		} else {
			logger.error("Could not get entityManager in updateEntity method");
			return 1;
		}
	}

	/**
	 * This method returns a list of entities which is retrieved from the database based on the query which is passed to this method.
	 * 
	 * @param query
	 *        The query which needs to be passed
	 * @return The list of entities
	 */
	public List getEntities(String query) {
		List returnList = new ArrayList();
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		if (entityManager != null) {
			logger.info("Obtained an entityManager in getEntities method");
			entityManager.getTransaction().begin();
			Query queryObj = entityManager.createQuery(query);
			returnList = queryObj.getResultList();
			entityManager.getTransaction().commit();
			entityManager.close();
		} else {
			logger.error("Could not get entityManager in getEntities method");
		}
		return returnList;
	}
}
